/**
 * @file calculate_score.c
 * @brief 评分计算模块实现
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "calculate_score.h"
#include "score_engine.h"
#include "feature_extractor.h"
#include "log.h"
#if !defined(USE_NEW_DIMENSIONS)
#define USE_NEW_DIMENSIONS 1 /* 默认开启新五维度: 1=新维度, 0=旧维度 */
#endif
#if USE_NEW_DIMENSIONS
#include "technique_score.h"
#endif


// 全局变量：节奏帧偏差，正值表示慢了，负值表示快了
static int rhythm_frame_offset = 0;
static int sentence_start_idx = 0;
static int sentence_end_idx = 0;
static int global_sentence_counter = 0; // 计数已评分的句子数
static float global_overall_accum = 0.0f; // 累加综合分(0-100)
// 固定能量活跃阈值(0-1范围, 根据特征归一化情况可调整)
#define ENERGY_ACTIVE_FIXED_THRESHOLD 0.00002f
// 句子内活跃帧最小比例阈值
#define ACTIVE_FRAME_RATIO_THRESHOLD 0.1f
// 用户特征与基准特征帧对齐偏移(0=不偏移, 1=用户整体后移一帧)
// TODO: TEST
#ifndef USER_FRAME_SHIFT
#define USER_FRAME_SHIFT 1
#endif
// 最大偏差值
#define MAX_OFFSET 5

// 节奏评分方法: 0=按句起始, 1=按每个字onset(十二平均律)
// TODO: TEST
#ifndef RHYTHM_METHOD_CHAR
#define RHYTHM_METHOD_CHAR 1
#endif

// ---------- Pitch 平滑参数 ----------
#ifndef PITCH_SMOOTH_ENABLE
#define PITCH_SMOOTH_ENABLE 1   // 1 = 开启用户音高平滑, 0 = 关闭
#endif
#define PITCH_MEDIAN_WIN 3      // 中值滤波窗口长度(3 或 5 均可, 必须为奇数)
#define PITCH_EMA_ALPHA 0.4f    // 指数移动平均系数(0-1, 越小越平滑)


// 获取当前节奏帧偏差值 - 内部函数
static int get_rhythm_frame_offset(void) {
    return rhythm_frame_offset;
}

// 设置节奏帧偏差值 - 内部函数
static void set_rhythm_frame_offset(int offset) {
    rhythm_frame_offset = offset;
}

// 默认权重常量定义
static const ScoreWeights DEFAULT_WEIGHTS = {
    .pitch_weight      = 0.30,  // 30% - 音准最重要
    .rhythm_weight     = 0.25,  // 25% - 节奏次之
    .timbre_weight     = 0.15,  // 15% - 音色
    .emotion_weight    = 0.15,  // 15% - 情感表达
    .breath_weight     = 0.10,  // 10% - 气息控制
    .brightness_weight = 0.05   // 5%  - 明亮度影响较小
};

// 流行歌曲权重
static const ScoreWeights POP_WEIGHTS = {
    .pitch_weight      = 0.35,  // 更注重音准
    .rhythm_weight     = 0.25,
    .timbre_weight     = 0.15,
    .emotion_weight    = 0.15,
    .breath_weight     = 0.05,
    .brightness_weight = 0.05
};

// 民族歌曲权重
static const ScoreWeights FOLK_WEIGHTS = {
    .pitch_weight      = 0.25,
    .rhythm_weight     = 0.20,
    .timbre_weight     = 0.25,  // 更注重音色特点
    .emotion_weight    = 0.15,
    .breath_weight     = 0.10,
    .brightness_weight = 0.05
};

// 说唱音乐权重
static const ScoreWeights RAP_WEIGHTS = {
    .pitch_weight      = 0.10,  // 音准相对不那么重要
    .rhythm_weight     = 0.50,  // 强调节奏感
    .timbre_weight     = 0.15,
    .emotion_weight    = 0.15,
    .breath_weight     = 0.05,
    .brightness_weight = 0.05
};

// 简单难度系数
static const DifficultyFactors EASY_FACTORS = {
    .pitch_tolerance = 1.5f,    // 音准误差容忍度高50%
    .rhythm_tolerance = 1.3f,   // 节奏误差容忍度高30%
    .other_tolerances = 1.2f    // 其他维度容忍度高20%
};

// 普通难度系数
static const DifficultyFactors NORMAL_FACTORS = {
    .pitch_tolerance = 1.0f,    // 标准容忍度
    .rhythm_tolerance = 1.0f,
    .other_tolerances = 1.0f
};

// 困难难度系数
static const DifficultyFactors HARD_FACTORS = {
    .pitch_tolerance = 0.8f,    // 音准误差容忍度降低20%
    .rhythm_tolerance = 0.9f,   // 节奏误差容忍度降低10%
    .other_tolerances = 0.9f    // 其他维度容忍度降低10%
};

// 专家难度系数
static const DifficultyFactors EXPERT_FACTORS = {
    .pitch_tolerance = 0.6f,    // 音准误差容忍度降低40%
    .rhythm_tolerance = 0.7f,   // 节奏误差容忍度降低30%
    .other_tolerances = 0.8f    // 其他维度容忍度降低20%
};

// 评分曲线系数
static const float PITCH_CURVE_FACTOR = 8.0f;
static const float RHYTHM_CURVE_FACTOR = 7.0f;
static const float TIMBRE_CURVE_FACTOR = 10.0f;
static const float EMOTION_CURVE_FACTOR = 8.0f;
static const float BREATH_CURVE_FACTOR = 8.0f;
static const float BRIGHTNESS_CURVE_FACTOR = 7.0f;

// -------------------- 工具函数 --------------------
// 交换两个float
static inline void swap_float(float* a, float* b) {
    float t = *a; *a = *b; *b = t;
}

#if PITCH_SMOOTH_ENABLE
// 取三个值的中位数 (窗口3)
static inline float median3(float a, float b, float c) {
    if (a > b) { float t = a; a = b; b = t; }
    if (b > c) { float t = b; b = c; c = t; }
    if (a > b) { float t = a; a = b; b = t; }
    return b;
}

// 三点均值
static inline float mean3(float a, float b, float c) {
    return (a + b + c) / 3.0f;
}
#endif

// 原地快速选择: 使得arr[k]就位，左边<=arr[k]，右边>=arr[k]
static void quickselect(float* arr, int left, int right, int k) {
    while (left < right) {
        float pivot = arr[(left + right) / 2];
        int i = left, j = right;
        while (i <= j) {
            while (arr[i] < pivot) ++i;
            while (arr[j] > pivot) --j;
            if (i <= j) {
                swap_float(&arr[i], &arr[j]);
                ++i; --j;
            }
        }
        if (k <= j) {
            right = j;
        } else if (k >= i) {
            left = i;
        } else {
            return; // k 已就位
        }
    }
}
// ---------------------------------------------------------------------

// 从引擎配置获取评分模块所需参数配置
void prepare_score_config_from_engine_config(const ScoreEngineConfig* engine_config, 
                                          PitchScoreConfig* pitch_config,
                                          RhythmScoreConfig* rhythm_config,
                                          BrightnessScoreConfig* brightness_config,
                                          BreathScoreConfig* breath_config,
                                          EmotionScoreConfig* emotion_config,
                                          TimbreScoreConfig* timbre_config) {
    if (!engine_config || !pitch_config || !rhythm_config || !brightness_config ||
        !breath_config || !emotion_config || !timbre_config) {
        return;
    }
    
    // 获取难度系数
    DifficultyFactors factors;
    if (engine_config->custom_factors) {
        // 使用自定义难度系数
        factors = *engine_config->custom_factors;
    } else {
        // 使用预设难度系数
        switch (engine_config->difficulty) {
            case DIFFICULTY_EASY:
                factors = EASY_FACTORS;
                break;
                
            case DIFFICULTY_NORMAL:
                factors = NORMAL_FACTORS;
                break;
                
            case DIFFICULTY_HARD:
                factors = HARD_FACTORS;
                break;
                
            case DIFFICULTY_EXPERT:
                factors = EXPERT_FACTORS;
                break;
                
            default:
                factors = NORMAL_FACTORS;
                break;
        }
    }
    
    // 设置各维度评分配置
    pitch_config->tolerance = factors.pitch_tolerance;
    pitch_config->dev_weight = 0.7f;
    pitch_config->std_weight = 0.3f;
    pitch_config->curve_factor = PITCH_CURVE_FACTOR;
    
    rhythm_config->tolerance = factors.rhythm_tolerance;
    rhythm_config->curve_factor = RHYTHM_CURVE_FACTOR;
    
    brightness_config->tolerance = factors.other_tolerances;
    brightness_config->dev_weight = 0.7f;
    brightness_config->std_weight = 0.3f;
    brightness_config->curve_factor = BRIGHTNESS_CURVE_FACTOR;
    
    breath_config->energy_weight = 0.5f;
    breath_config->hnr_weight = 0.5f;
    breath_config->tolerance = factors.other_tolerances;
    breath_config->curve_factor = BREATH_CURVE_FACTOR;
    
    emotion_config->tolerance = 0.8f*factors.other_tolerances;          /* 相关系数容忍度, corr>=0.8 记满分 */
    emotion_config->gamma     = 1.5f/factors.other_tolerances;          /* 低分段压缩指数 γ */
    emotion_config->curve_factor = EMOTION_CURVE_FACTOR;
    
    timbre_config->tolerance = factors.other_tolerances;
    timbre_config->dev_weight = 0.7f;
    timbre_config->std_weight = 0.3f;
    timbre_config->curve_factor = TIMBRE_CURVE_FACTOR;
}

// 应用评分曲线
int apply_score_curve(float raw_score, float curve_factor) {
    // 使用S形曲线将0-1范围映射到0-100范围
    float mapped = 1.0f / (1.0f + expf(-curve_factor * (raw_score - 0.5f)));
    
    // 转换为0-100整数分数
    int score = (int)(mapped * 100.0f + 0.5f);
    
    // 限制在0-100范围内
    if (score < 0) score = 0;
    if (score > 100) score = 100;
    
    return score;
}

// 计算音准得分
float calculate_pitch_score(const ScoreFeatureBuffers* buffers, int frame_idx_start, int frame_idx_end, const PitchScoreConfig* config) {
    // -------- 音准评分 (容忍度命中率) --------
    // 评分规则：
    // 1) 统计本句所有有效帧 (基准和用户 pitch 均 > 0)
    // 2) 计算每帧音高差(半音), 若 <= 容忍阈值记为"命中"
    // 3) 得分 = 命中帧数 / 有效帧数, 范围0~1
    
    if (!buffers || !config || !buffers->pitch_buffer || !buffers->pitch_buffer_base ||
        frame_idx_start < 0 || frame_idx_end >= buffers->buffer_size || frame_idx_start > frame_idx_end) {
        return 0.0f;
    }

    // Align indices considering USER_FRAME_SHIFT
    if (frame_idx_end - USER_FRAME_SHIFT < frame_idx_start) {
        return 0.0f;
    }
 
    // ------ 步骤 1: 计算容忍阈值 ------
    // 半音容忍度: 0.5 个半音 * tolerance 系数
    const float BASE_TOL_SEMI = 3.0f;
    float tol_semi = BASE_TOL_SEMI * (config->tolerance > 0.0f ? config->tolerance : 1.0f);
 
    int total_frames = 0; // 有效帧数
    int within_tol   = 0; // 命中帧数
 
    float* p_base_buf = buffers->pitch_buffer_base;
    float* p_user_buf = buffers->pitch_buffer;
 
    for (int i = frame_idx_start; i <= frame_idx_end - USER_FRAME_SHIFT; ++i) {
        float p_base = p_base_buf[i];
        float p_user = p_user_buf[i + USER_FRAME_SHIFT];
 
//        // 只统计基准和用户 pitch 都有效的帧
//        if (p_base <= 0.0f || p_user <= 0.0f) {
//            continue;
//        }
        total_frames++;
 
        float diff = fabsf(p_user - p_base); // 半音差
        if (diff >= 12.0f) {
            diff = fmodf(diff, 12.0f); // 折叠到 0~12 半音范围，允许跨倍频
        }
        const float thr = ENERGY_ACTIVE_FIXED_THRESHOLD;
        float e_lin = powf(10.0f, buffers->energy_buffer[i] / 10.0f);
        if (diff <= tol_semi && e_lin > thr) {
            within_tol++; // 计为命中
        }
    }
 
    if (total_frames == 0) {
        return 0.0f;
    }
 
    // ------ 步骤 2: 计算得分 ------
    float score = (float)within_tol / (float)total_frames; // 命中率

    LOGD("Pitch stats (new rule): within_tol=%d / total=%d, tol_semi=%.3f, score=%.4f\n",
           within_tol, total_frames, tol_semi, score);
    if (score < 0.0f) score = 0.0f;
    if (score > 1.0f) score = 1.0f;
    return score;
}

// ------------------------------------------------------------
// 函数: is_sentence_active_by_energy
// 描述: 判断[start_idx,end_idx]区间内实时能量活跃帧比例是否达标
// 返回: 1 = 句子有效, 0 = 句子无效
// ------------------------------------------------------------
static int is_sentence_active_by_energy(const ScoreFeatureBuffers* buffers,
                                        int start_idx, int end_idx)
{
    if (!buffers || !buffers->energy_buffer ||
        start_idx < 0 || end_idx <= start_idx ||
        end_idx >= buffers->buffer_size) {
        return 0;
    }

    int total_frames = end_idx - start_idx + 1;
    int active_frames = 0;

    const float thr = ENERGY_ACTIVE_FIXED_THRESHOLD;

    for (int i = start_idx; i <= end_idx; ++i) {
        /* 将 dB 能量值转换为线性能量 */
        float e_lin = powf(10.0f, buffers->energy_buffer[i] / 10.0f);
        if (e_lin > thr) {
            ++active_frames;
        }
    }

    float ratio = (float)active_frames / (float)total_frames;
    return (ratio >= ACTIVE_FRAME_RATIO_THRESHOLD);
}
// ------------------------------------------------------------

// 其他评分计算函数实现
#if RHYTHM_METHOD_CHAR
float calculate_rhythm_score_char(const ScoreFeatureBuffers* buffers,
                                 int frame_idx_end,
                                 const RhythmScoreConfig* config)
{
    if (!buffers || !config || frame_idx_end < 0 || frame_idx_end >= buffers->buffer_size) {

        printf("[RhythmChar] invalid input, frame_idx_end=%d / size=%d\n", frame_idx_end, buffers ? buffers->buffer_size : -1);
        return -1.0f;
    }

    // 1. 解析句起始、结束帧 (已由 detect_sentence_start_by_rhythm 设置 sentence_start_idx)
    sentence_start_idx = detect_sentence_start_by_rhythm(buffers, frame_idx_end);
    if (sentence_start_idx < 0) {

        printf("[RhythmChar] sentence_start not found for end=%d\n", frame_idx_end);
        return -1.0f;
    }

    // ---- 句子能量有效性检测 ----
    if (!is_sentence_active_by_energy(buffers, sentence_start_idx, frame_idx_end)) {
        printf("Rhythm calculation: sentence inactive (energy)\n");
        return -1;
    }

    int start_idx = sentence_start_idx;
    int end_idx   = frame_idx_end;

    printf("[RhythmChar] Base sentence range: %d-%d (len=%d)\n", start_idx, end_idx, end_idx - start_idx + 1);

    // 2. 枚举该区间基准 onset (rhythm==3)
    int base_onsets[128];
    int base_cnt = 0;
    // 将句首 (rhythm==1) 作为第一个基准 onset
    if (base_cnt < 128) base_onsets[base_cnt++] = start_idx;

    // 2. 枚举该区间基准 onset (rhythm==3)
    for (int i = start_idx; i <= end_idx; ++i) {
        if (fabsf(buffers->rhythm_buffer_base[i] - 3.0f) < 0.01f) {
            if (base_cnt < 128) base_onsets[base_cnt++] = i;
        }
    }
    if (base_cnt == 0) {

        printf("[RhythmChar] no base onset between %d-%d\n", start_idx, end_idx);
        return -1.0f; // 无基准 onset
    }

    printf("[RhythmChar] base_onsets(%d):", base_cnt);
    for (int i = 0; i < base_cnt; ++i) {
        printf(" %d", base_onsets[i]);
    }
    printf("\n");

    // -------- 用户 onset 搜索范围 --------
    int user_search_start = start_idx - MAX_OFFSET;
    if (user_search_start < 0) user_search_start = 0;
    int user_search_end   = end_idx;

    // 计算自适应阈值 (在扩展后的搜索区间内)
    float mean = 0.0f, std = 0.0f; int n = 0;
    for (int i = user_search_start; i <= user_search_end; ++i) {
        float v = buffers->flux_buffer ? buffers->flux_buffer[i] : 0.0f;
        mean += v; ++n;
    }
    if (n > 0) mean /= n; else mean = 0.0f;
    for (int i = user_search_start; i <= user_search_end; ++i) {
        float diff = (buffers->flux_buffer ? buffers->flux_buffer[i] : 0.0f) - mean;
        std += diff * diff;
    }
    std = (n > 0) ? sqrtf(std / n) : 0.0f;
    float thr = mean + 1.5f * std;

    // 3. 检测用户 onset：使用 flux 峰值
    int user_onsets[256];
    int user_cnt = 0;
    for (int i = user_search_start + 1; i < user_search_end - 1; ++i) {
        float cur = buffers->flux_buffer ? buffers->flux_buffer[i] : 0.0f;
        if (cur > thr && cur > (buffers->flux_buffer ? buffers->flux_buffer[i-1] : 0.0f) &&
            cur > (buffers->flux_buffer ? buffers->flux_buffer[i+1] : 0.0f)) {
            if (user_cnt < 256) user_onsets[user_cnt++] = i;
        }
    }

    printf("[RhythmChar] user_onsets(%d) [search %d-%d]:", user_cnt, user_search_start, user_search_end);
    for (int i = 0; i < user_cnt; ++i) {
        printf(" %d", user_onsets[i]);
    }
    printf("\n");

    if (user_cnt == 0) {
        printf("[RhythmChar] no user onset detected, thr=%.6f, start=%d, end=%d -> score 0\n", thr, user_search_start, user_search_end);
        return 0.0f; // 赋 0 分，但句子依然有效
    }

    // 4. 匹配: 对每个 base onset 找最近 user onset (贪心)
    int used_flags[256] = {0};
    float abs_sum = 0.0f;
    int matched = 0;
    for (int b = 0; b < base_cnt; ++b) {
        int bi = base_onsets[b];
        int best_u = -1; int best_d = MAX_OFFSET+1;
        for (int u = 0; u < user_cnt; ++u) {
            if (used_flags[u]) continue;
            int diff = abs(user_onsets[u] - bi);
            if (diff < best_d) { best_d = diff; best_u = u; }
        }
        if (best_u >= 0) {
            used_flags[best_u] = 1;
            abs_sum += (float)best_d;
            matched++;
        } else {
            abs_sum += (float)MAX_OFFSET; // 未找到匹配当作最大偏差
        }
    }

    if (matched == 0) {
        printf("[RhythmChar] no matched onset (base_cnt=%d, user_cnt=%d) -> score 0\n", base_cnt, user_cnt);
        return 0.0f; // 无匹配直接 0 分
    }

    float avg_offset = abs_sum / (float)base_cnt;
    printf("[RhythmChar] avg_offset=%.2f frames (base_cnt=%d)\n", avg_offset, base_cnt);

    avg_offset /= config->tolerance; // 容错调整
    float score = expf(-0.04f * avg_offset);
    if (score < 0.0f) score = 0.0f;
    if (score > 1.0f) score = 1.0f;

    return score;
}
#endif // RHYTHM_METHOD_CHAR

float calculate_rhythm_score(const ScoreFeatureBuffers* buffers, int frame_idx, const RhythmScoreConfig* config) {
    if (!buffers || !config || frame_idx < 0 || frame_idx >= buffers->buffer_size) {
        return 0.0f;
    }
    
    // 查找当前句的起始帧位置（基准文件中的标记）
    sentence_start_idx = detect_sentence_start_by_rhythm(buffers, frame_idx);

    // ---- 句子能量有效性检测 ----
    if (!is_sentence_active_by_energy(buffers, sentence_start_idx, frame_idx)) {
        printf("Rhythm calculation: sentence inactive (energy)\n");
        return -1;
    }

    //offset 为给后需要算法计算使用的偏差值
    //offsetscore 
    //如果找不到actual_onset，则认为偏差最大，暂定20
    int offset = 0, offsetscore=0;
    
    // 计算节奏帧偏差，偏差为0表示节奏完美匹配
    // 如果找不到起始点，则退出 
    if (sentence_start_idx >= 0) {
        // 使用频谱通量方法检测用户实际的onset点
        //int actual_onset = detect_onset_by_flux(buffers, frame_idx, MAX_OFFSET); // 使用适当的搜索范围
        int actual_onset = detect_onset_by_energy(buffers, frame_idx, MAX_OFFSET); // 使用适当的搜索范围
        
        if (actual_onset >= 0) {
            // 计算用户实际onset与基准onset的偏差
            // 正值表示慢了（实际onset晚于基准onset）
            // 负值表示快了（实际onset早于基准onset）
            offset = actual_onset - sentence_start_idx;
            offsetscore = offset;
            
            // 打印节奏偏差信息
            printf("Rhythm calculation: Sentence start frame=%d, Actual onset frame=%d, Offset=%d frames\n", 
                   sentence_start_idx, actual_onset, offset);
        } else {
            offsetscore = MAX_OFFSET;
            printf("Rhythm calculation: Sentence start frame=%d, No actual onset detected\n", sentence_start_idx);
        }
    } else {
        printf("Rhythm calculation: No sentence start point found\n");
        return -1;
    }

    set_rhythm_frame_offset(offset);
    
    // 实现节奏评分算法，使用rhythm_frame_offset
    // 节奏评分主要基于节奏帧偏差的绝对值 - 偏差越小分数越高
    float abs_offset = (float)fabsf((float)offsetscore);
    
    // 应用容错度调整
    abs_offset /= config->tolerance;
    printf("abs_offset: %f, tolerance: %f\r\n", abs_offset, config->tolerance);
    
    // 转换为0-1分数，偏差越小分数越高
    float score = expf(-0.05f * abs_offset);
    
    // 限制在0-1范围
    if (score < 0.0f) score = 0.0f;
    if (score > 1.0f) score = 1.0f;
    
    return score;
}

float calculate_brightness_score(const ScoreFeatureBuffers* buffers, int frame_idx_start, int frame_idx_end, const BrightnessScoreConfig* config) {
    // 参数校验
    if (!buffers || !config || !buffers->brightness_buffer || !buffers->brightness_buffer_base ||
        frame_idx_start < 0 || frame_idx_end >= buffers->buffer_size || frame_idx_start > frame_idx_end) {
        return 0.0f;
    }

    int capacity = frame_idx_end - frame_idx_start + 1;
    float* dev = (float*)malloc(capacity * sizeof(float));
    if (!dev) return 0.0f;

    int count = 0;
    float* b_base_buf = buffers->brightness_buffer_base;
    float* b_user_buf = buffers->brightness_buffer;

    // 对齐：用户帧 = 基准帧 + USER_FRAME_SHIFT
    if (frame_idx_end - USER_FRAME_SHIFT < frame_idx_start) { free(dev); return 0.0f; }
    for (int i = frame_idx_start; i <= frame_idx_end - USER_FRAME_SHIFT; ++i) {
        float b_base = b_base_buf[i];
        float b_user = b_user_buf[i + USER_FRAME_SHIFT];
        if (b_base > 0.0f && b_user > 0.0f) {
            dev[count++] = fabsf(b_user / b_base - 1.0f);
        }
    }

    if (count == 0) {
        free(dev);
        return 0.0f;
    }

    // 保留90%小偏差
    int keep_cnt = (int)(count * 0.9f + 0.5f);
    if (keep_cnt <= 0) keep_cnt = count;
    quickselect(dev, 0, count - 1, keep_cnt - 1);

    // Welford
    float mean = 0.0f, M2 = 0.0f; int n = 0;
    for (int i = 0; i < keep_cnt; ++i) {
        float x = dev[i];
        n++;
        float delta = x - mean;
        mean += delta / n;
        float delta2 = x - mean;
        M2 += delta * delta2;
    }
    float variance = (n > 1) ? (M2 / n) : 0.0f;
    float std_dev = sqrtf(variance);

    printf("Brightness stats: mean_dev=%.6f, std_dev=%.6f, frames=[%d-%d] (user+1 alignment), used=%d\n",
           mean, std_dev, frame_idx_start, frame_idx_end, keep_cnt);

    free(dev);

    float combined = config->dev_weight * mean + config->std_weight * std_dev;
    float norm = combined / (config->tolerance > 0.0f ? config->tolerance : 1.0f);
    float score = expf(-2.0f * norm); // 系数3

    if (score < 0.0f) score = 0.0f;
    if (score > 1.0f) score = 1.0f;
    return score;
}

float calculate_breath_score(const ScoreFeatureBuffers* buffers, int frame_idx_start, int frame_idx_end, const BreathScoreConfig* config) {
    // 根据新需求：平均能量与能量标准差各 50% 权重
    if (!buffers || !config || !buffers->energy_buffer || !buffers->energy_buffer_base ||
        frame_idx_start < 0 || frame_idx_end >= buffers->buffer_size || frame_idx_start > frame_idx_end) {
        return 0.0f;
    }

    // 考虑 USER_FRAME_SHIFT 对齐, 确保不会越界
    if (frame_idx_end - USER_FRAME_SHIFT < frame_idx_start) {
        return 0.0f;
    }

    int start_idx = frame_idx_start + 10;
    int end_idx   = frame_idx_end - 10 - USER_FRAME_SHIFT;

    if (end_idx <= start_idx) {
        return 1.0f; /* 剩余帧不足，直接满分 */
    }

    // ---------------- 统计均值与标准差（Welford） ----------------
    float mean_user = 0.0f, M2_user = 0.0f;
    float mean_base = 0.0f, M2_base = 0.0f;
    int   n = 0;

    for (int i = start_idx; i <= end_idx; ++i) {
        float e_base = buffers->energy_buffer_base[i];               // dB
        float e_user = buffers->energy_buffer[i + USER_FRAME_SHIFT]; // dB

        n++;

        // --- user 能量 (dB) ---
        float delta_u = e_user - mean_user;
        mean_user += delta_u / n;
        float delta2_u = e_user - mean_user;
        M2_user += delta_u * delta2_u;

        // --- base 能量 (dB) ---
        float delta_b = e_base - mean_base;
        mean_base += delta_b / n;
        float delta2_b = e_base - mean_base;
        M2_base += delta_b * delta2_b;
    }

    if (n <= 1) {
        return 1.0f; // 帧数太少, 直接满分
    }

    float sigma_user = sqrtf(M2_user / n);
    float sigma_base = sqrtf(M2_base / n);

    // ---------------- Score_mean ----------------
    // ΔdB 方案：ΔdB = mean_user - mean_base (单位 dB)
    float score_mean = 1.0f;
    {
        float delta_db = mean_user - mean_base; // 若 >=0 表示不低于原唱
        if (delta_db < 0.0f) {
            float dev_db = -delta_db; // 正值，用户更弱

            /* 容忍度: 基础 6 dB × tolerance 系数 */
            float tol_db = 6.0f * (config->tolerance > 0.0f ? config->tolerance : 1.0f);
            float norm_mean = dev_db / tol_db;

            score_mean = expf(-0.5f * norm_mean);
        }
    }

    // ---------------- Score_std ----------------
    float score_std = 1.0f;
    if (sigma_base > 1e-6f) {
        /* 与 score_mean 一致：按差值(绝对差)扣分，不分方向 */
        float dev_std = fabsf(sigma_user - sigma_base);           /* 绝对差值 */

        /* 容忍度: 基准 σ × tolerance 系数 */
        float tol_sigma = sigma_base * (config->tolerance > 0.0f ? config->tolerance : 1.0f);
        if (tol_sigma < 1e-6f) tol_sigma = 1e-6f;

        float norm_std = dev_std / tol_sigma;
        score_std = expf(-0.5f * norm_std);                       /* 使用同样指数系数 0.5 */
    }

    // ---------------- 合成 ----------------
    float score = 0.5f * score_mean + 0.5f * score_std;
    //float score = score_mean;

    printf("Breath stats: mean_user=%.6f, mean_base=%.6f, sigma_user=%.6f, sigma_base=%.6f, score_mean=%.6f, score_std=%.6f, score=%.6f\n",
           mean_user, mean_base, sigma_user, sigma_base, score_mean, score_std, score);

    // 限制范围
    if (score < 0.0f) score = 0.0f;
    if (score > 1.0f) score = 1.0f;
    return score;
}

float calculate_emotion_score(const ScoreFeatureBuffers* buffers, int frame_idx_start, int frame_idx_end, const EmotionScoreConfig* config) {

    /* ---------------- 新情感评分规则 ----------------
       1. 对用户与基准能量曲线做 10 点均值平滑 (中心±4/5)
       2. 计算皮尔逊相关系数 corr
       3. corr<0 视为 0
       4. 使用指数函数调节: score = exp( -k * (1 - corr) ), 取 k=2
    */
    if (!buffers || !config || !buffers->energy_buffer || !buffers->energy_buffer_base ||
        frame_idx_start < 0 || frame_idx_end >= buffers->buffer_size || frame_idx_start > frame_idx_end) {
        return 0.0f;
    }

    /* 对齐检查 */
    if (frame_idx_end - USER_FRAME_SHIFT < frame_idx_start) {
        return 0.0f;
    }

    int start_idx = frame_idx_start;
    int end_idx   = frame_idx_end - USER_FRAME_SHIFT;

    const int LAG_STEP   = 2;   /* 每次偏移 2 帧 */
    const int LAG_TRIALS = 5;   /* 共尝试 0,2,4,6,8 帧 */
    const int LAG_MAX    = (LAG_TRIALS - 1) * LAG_STEP;

    /* ---------- Step-0: 预先计算 10 点滑窗均值 ---------- */
    int len_base = end_idx - start_idx + 1;                      /* 基准平滑曲线长度 */
    int user_start_idx = frame_idx_start + USER_FRAME_SHIFT;     /* 用户曲线起点(考虑固定对齐) */
    int user_end_idx   = end_idx + USER_FRAME_SHIFT;             /* 用户曲线终点 */
    int len_user = user_end_idx - user_start_idx + 1;            /* 用户平滑曲线长度 */

    double* smooth_base = (double*)malloc(len_base * sizeof(double));
    double* smooth_user = (double*)malloc(len_user * sizeof(double));
    if (!smooth_base || !smooth_user) {
        if (smooth_base) free(smooth_base);
        if (smooth_user) free(smooth_user);
        return 0.0f; /* 内存不足，直接 0 分 */
    }

    /* ---- 平滑基准 ---- */
    for (int i = start_idx; i <= end_idx; ++i) {
        double sum_b = 0.0; int cnt_b = 0;
        for (int off = -4; off <= 5; ++off) {
            int idx = i + off;
            if (idx < start_idx) idx = start_idx;
            if (idx > end_idx)   idx = end_idx;
            sum_b += buffers->energy_buffer_base[idx];
            ++cnt_b;
        }
        smooth_base[i - start_idx] = sum_b / cnt_b;
    }

    /* ---- 平滑用户 ---- */
    for (int j = user_start_idx; j <= user_end_idx; ++j) {
        double sum_u = 0.0; int cnt_u = 0;
        for (int off = -4; off <= 5; ++off) {
            int idx = j + off;
            if (idx < frame_idx_start) idx = frame_idx_start;
            if (idx > frame_idx_end)   idx = frame_idx_end;
            sum_u += buffers->energy_buffer[idx];
            ++cnt_u;
        }
        smooth_user[j - user_start_idx] = sum_u / cnt_u;
    }

    /* ---------- Step-1: 延时扫描 ---------- */
    double best_corr = -2.0; /* 初始化为不可能值 */
    int    best_lag  = 0;
    int    best_n    = 0;

    for (int lag_idx = 0; lag_idx < LAG_TRIALS; ++lag_idx) {
        int lag = lag_idx * LAG_STEP;
        int valid_len = len_base - lag; /* 可对齐的有效帧数 */
        if (valid_len < 2) continue;

        /* 累积量 */
        double sum_x = 0.0, sum_y = 0.0;
        double sum_xx = 0.0, sum_yy = 0.0, sum_xy = 0.0;

        for (int k = 0; k < valid_len; ++k) {
            double y = smooth_base[k];                     /* 基准 */
            /* 用户索引映射: base idx = start_idx + k  ==> user idx = user_start_idx + k + lag */
            double x = smooth_user[k + lag];               /* 用户 (已平滑) */

            sum_x  += x;
            sum_y  += y;
            sum_xx += x * x;
            sum_yy += y * y;
            sum_xy += x * y;
        }

        double n = (double)valid_len;
        double cov   = sum_xy - n * (sum_x / n) * (sum_y / n);
        double var_x = sum_xx - n * (sum_x / n) * (sum_x / n);
        double var_y = sum_yy - n * (sum_y / n) * (sum_y / n);
        double denom = sqrt(var_x * var_y);
        double corr_tmp = 0.0;
        if (denom > 1e-9) {
            corr_tmp = cov / denom;
            if (corr_tmp > 1.0) corr_tmp = 1.0;
            if (corr_tmp < -1.0) corr_tmp = -1.0;
        }

        /* 计算当前延时对应得分并打印 */
        const float K_EMOTION_DBG = 1.5f / (config->tolerance > 0.0f ? config->tolerance : 1.0f);
        float score_tmp = expf(-K_EMOTION_DBG * (1.0f - (float)corr_tmp));
        printf("[EmotionLag] lag=%d, corr=%.6f, score=%.4f, n=%d\n", lag, corr_tmp, score_tmp, valid_len);

        /* 取最大相关系数 (允许负值, 之后统一裁剪) */
        if (corr_tmp > best_corr) {
            best_corr = corr_tmp;
            best_lag  = lag;
            best_n    = valid_len;
        }
    }

    /* 释放平滑曲线内存 */
    free(smooth_base);
    free(smooth_user);

    double corr = best_corr;

    if (corr < 0.0) corr = 0.0; /* 负值按 0 处理 */

    /* ---------- Step-2: 指数映射为分数 (corr) ---------- */
    const float K_EMOTION = 1.5f; /* 调节系数 */
    float score_corr = expf(-K_EMOTION * (1.0f - (float)corr));

    /* ---------- Step-3: 计算能量得分 ---------- */
    double sum_u_en = 0.0, sum_b_en = 0.0; int n_en = 0;
    for (int i = frame_idx_start; i <= frame_idx_end - USER_FRAME_SHIFT; ++i) {
        sum_b_en += (double)buffers->energy_buffer_base[i];
        sum_u_en += (double)buffers->energy_buffer[i + USER_FRAME_SHIFT];
        ++n_en;
    }
    float score_energy = 1.0f;
    float mean_b_db = 0.0f, mean_u_db = 0.0f;
    if (n_en > 0) {
        mean_b_db = (float)(sum_b_en / n_en);
        mean_u_db = (float)(sum_u_en / n_en);
        float delta_db = mean_b_db - mean_u_db; /* 用户更弱为正 */
        if (delta_db > 0.0f) {
            float tol_db = 6.0f * (config->tolerance > 0.0f ? config->tolerance : 1.0f);
            float norm = delta_db / tol_db;
            score_energy = expf(-0.5f * norm);
        }
        /* 打印能量均值与容忍度 */
        printf("Energy mean_u_db=%.6f, mean_b_db=%.6f, tol=%.2f\n", mean_u_db, mean_b_db, config->tolerance);
    }

    /* ---------- Step-4: 合成最终得分 ---------- */
    float score = 0.5f * score_corr + 0.5f * score_energy;

    printf("Emotion stats (NEW, lag scan): corr_max=%.6f, lag=%d, corr_score=%.4f, energy_score=%.4f, final_score=%.4f, frames=[%d-%d], n=%d\n",
           corr, best_lag, score_corr, score_energy, score, frame_idx_start, frame_idx_end, best_n);

    if (score < 0.0f) score = 0.0f;
    if (score > 1.0f) score = 1.0f;
    return score;
}

float calculate_timbre_score(const ScoreFeatureBuffers* buffers, int frame_idx_start, int frame_idx_end, const TimbreScoreConfig* config) {
    // 参数校验
    if (!buffers || !config || !buffers->timbre_buffer || !buffers->timbre_buffer_base ||
        frame_idx_start < 0 || frame_idx_end >= buffers->buffer_size || frame_idx_start > frame_idx_end) {
        return 0.0f;
    }

    int capacity = frame_idx_end - frame_idx_start + 1;
    float* dev = (float*)malloc(capacity * sizeof(float));
    if (!dev) return 0.0f;

    int count = 0;
    float* t_base_buf = buffers->timbre_buffer_base;
    float* t_user_buf = buffers->timbre_buffer;

    // 对齐：用户帧 = 基准帧 + USER_FRAME_SHIFT
    if (frame_idx_end - USER_FRAME_SHIFT < frame_idx_start) { free(dev); return 0.0f; }
    for (int i = frame_idx_start; i <= frame_idx_end - USER_FRAME_SHIFT; ++i) {
        float t_base = t_base_buf[i];
        float t_user = t_user_buf[i + USER_FRAME_SHIFT];
        // 仅在基准与用户音色特征有效时计算偏差
        if (t_base > 0.0f && t_user > 0.0f) {
            dev[count++] = fabsf(t_user - t_base) / t_base; // 相对偏差 ||F_u - F_b|| / ||F_b||
        }
    }

    if (count == 0) {
        free(dev);
        return 0.0f;
    }

    // 去除最大10%偏差，只保留90%较小偏差帧
    int keep_cnt = (int)(count * 0.9f + 0.5f);
    if (keep_cnt <= 0) keep_cnt = count;
    quickselect(dev, 0, count - 1, keep_cnt - 1);

    // 计算均值与标准差 (Welford 在线算法)
    float mean = 0.0f, M2 = 0.0f; int n = 0;
    for (int i = 0; i < keep_cnt; ++i) {
        float x = dev[i];
        n++;
        float delta = x - mean;
        mean += delta / n;
        float delta2 = x - mean;
        M2 += delta * delta2;
    }
    float variance = (n > 1) ? (M2 / n) : 0.0f;
    float std_dev = sqrtf(variance);

    printf("Timbre stats: mean_dev=%.6f, std_dev=%.6f, frames=[%d-%d] (user+%d alignment), used=%d\n",
           mean, std_dev, frame_idx_start, frame_idx_end, USER_FRAME_SHIFT, keep_cnt);

    free(dev);

    // 组合均值与标准差
    float combined = config->dev_weight * mean + config->std_weight * std_dev;

    // 归一化并映射到0-1
    float norm = combined / (config->tolerance > 0.0f ? config->tolerance : 1.0f);
    float score = expf(-2.0f * norm); // 系数 2 对应文档公式

    if (score < 0.0f) score = 0.0f;
    if (score > 1.0f) score = 1.0f;
    return score;
}

// 计算总体评分
int calculate_overall_score(const ScoreFeatureBuffers* buffers, int frame_idx,
                          ScoreResult* result, const ScoreEngineConfig* engine_config) {
    if (!buffers || !result || !engine_config || frame_idx < 0 || frame_idx >= buffers->buffer_size) {
        return ERROR_CONFIG_INVALID;
    }
    
    // 初始化结果标志为0（默认不返回得分）
    result->score_flag = 0;
    
    // 检查当前帧-MAX_OFFSET是否为句子结束帧（基准节奏值为2）
    // 只有在句子结束时才计算得分
    // 句子结束后又额外保存MAX_OFFSET帧个数，方便节奏偏差后续维度评分算法做偏移计算处理
    if ((frame_idx-MAX_OFFSET)<0 || buffers->rhythm_buffer_base == NULL || buffers->rhythm_buffer_base[frame_idx-MAX_OFFSET] != 2) {
        // 不是句子结束帧，不计算得分
        return ERROR_SUCCESS;
    }

    sentence_end_idx = frame_idx-MAX_OFFSET;
    
    // 是句子结束帧，继续计算得分
    
    // 创建各维度评分配置
    PitchScoreConfig pitch_config;
    RhythmScoreConfig rhythm_config;
    BrightnessScoreConfig brightness_config;
    BreathScoreConfig breath_config;
    EmotionScoreConfig emotion_config;
    TimbreScoreConfig timbre_config;
    
    // 从引擎配置准备评分配置
    prepare_score_config_from_engine_config(
        engine_config,
        &pitch_config,
        &rhythm_config,
        &brightness_config,
        &breath_config,
        &emotion_config,
        &timbre_config
    );
    
    // 计算各维度原始评分(0-1范围)
#if RHYTHM_METHOD_CHAR
    float rhythm_raw = calculate_rhythm_score_char(buffers, sentence_end_idx, &rhythm_config);
#else
    float rhythm_raw = calculate_rhythm_score(buffers, sentence_end_idx, &rhythm_config);
#endif

    float pitch_raw = 0;
    float brightness_raw = 0;
    float breath_raw = 0;
    float emotion_raw = 0;
    float timbre_raw = 0;
#if USE_NEW_DIMENSIONS
    float technique_raw = 0;
#endif
    // 如果节奏评分小于0，表示没有找到合适的句子起始点，得分为0
    if(rhythm_raw<0) {
        rhythm_raw = 0;
    }else{

        // 根据节奏评分结果，调整句子起始点和结束点
        // 暂时不对句子起始点和结束点进行调整
        // sentence_start_idx = sentence_start_idx + get_rhythm_frame_offset();
        // sentence_end_idx = sentence_end_idx + get_rhythm_frame_offset();

        pitch_raw = calculate_pitch_score(buffers, sentence_start_idx, sentence_end_idx, &pitch_config);
#if USE_NEW_DIMENSIONS
        technique_raw = calculate_technique_score(buffers, sentence_start_idx, sentence_end_idx, NULL);
        breath_raw = calculate_breath_score(buffers, sentence_start_idx, sentence_end_idx, &breath_config);
        emotion_raw = calculate_emotion_score(buffers, sentence_start_idx, sentence_end_idx, &emotion_config);
        /* 明亮度与音色评分在新维度下不再计算 */
        brightness_raw = 0.0f;
        timbre_raw = 0.0f;
#else
        brightness_raw = calculate_brightness_score(buffers, sentence_start_idx, sentence_end_idx, &brightness_config);
        breath_raw = calculate_breath_score(buffers, sentence_start_idx, sentence_end_idx, &breath_config);
        emotion_raw = calculate_emotion_score(buffers, sentence_start_idx, sentence_end_idx, &emotion_config);
        timbre_raw = calculate_timbre_score(buffers, sentence_start_idx, sentence_end_idx, &timbre_config);
#endif
    }

    // 应用评分曲线得到最终评分(0-100范围)
    result->pitch_score = apply_score_curve(pitch_raw, pitch_config.curve_factor);
    result->rhythm_score = apply_score_curve(rhythm_raw, rhythm_config.curve_factor);
#if USE_NEW_DIMENSIONS
    /* brightness_score 字段复用为 technique_score */
    result->brightness_score = apply_score_curve(technique_raw, 8.0f /* 同 TechniqueScore 默认曲线因子 */);
    result->breath_score = apply_score_curve(breath_raw, breath_config.curve_factor);
    result->emotion_score = apply_score_curve(emotion_raw, emotion_config.curve_factor);
    result->timbre_score = 0; /* 不使用 */
#else
    result->brightness_score = apply_score_curve(brightness_raw, brightness_config.curve_factor);
    result->breath_score = apply_score_curve(breath_raw, breath_config.curve_factor);
    result->emotion_score = apply_score_curve(emotion_raw, emotion_config.curve_factor);
    result->timbre_score = apply_score_curve(timbre_raw, timbre_config.curve_factor);
#endif

    result->rhythm_score = result->rhythm_score*0.5+result->pitch_score*0.5;
    result->emotion_score = result->emotion_score*0.5+result->pitch_score*0.5;
//    result->emotion_score = result->emotion_score*0.7+result->pitch_score*0.3;
    // 获取权重
    ScoreWeights weights;
    if (engine_config->custom_weights) {
        // 使用自定义权重
        weights = *engine_config->custom_weights;
    } else {
        // 使用预设权重
        switch (engine_config->style) {
            case SONG_STYLE_POP:
                weights = POP_WEIGHTS;
                break;
                
            case SONG_STYLE_FOLK:
                weights = FOLK_WEIGHTS;
                break;
                
            case SONG_STYLE_RAP:
                weights = RAP_WEIGHTS;
                break;
                
            default:
                weights = DEFAULT_WEIGHTS;
                break;
        }
    }
    
    // 计算总分(加权平均)
    float overall_raw = 
        result->pitch_score * weights.pitch_weight + 
        result->rhythm_score * weights.rhythm_weight + 
#if USE_NEW_DIMENSIONS
        result->brightness_score * (weights.brightness_weight + weights.timbre_weight) + /* 技巧权重 = 明亮度 + 音色 */
        result->breath_score * weights.breath_weight + 
        result->emotion_score * weights.emotion_weight;
#else
        result->brightness_score * weights.brightness_weight + 
        result->breath_score * weights.breath_weight + 
        result->emotion_score * weights.emotion_weight + 
        result->timbre_score * weights.timbre_weight;
#endif

    overall_raw = overall_raw * 0.01f;
    
    // 转换本句总分到0-100范围
    int sentence_overall_score = (int)(overall_raw * 100.0f + 0.5f);

    // ---- 累计全局平均分 ----
    global_overall_accum += (float)sentence_overall_score;
    float overall_avg = global_overall_accum / (float)(global_sentence_counter + 1);
    //result->overall_score = (int)(overall_avg + 0.5f);
    result->overall_score = (int)(sentence_overall_score + 0.5f);
    
    
    // 由于是句子结束帧，设置结果标志为1
    result->score_flag = 1;
    global_sentence_counter++;
    
    return ERROR_SUCCESS;
}

// ---------- 新增: 评分缓冲区管理实现 ----------
ScoreFeatureBuffers* create_calculate_score_buffers(int buffer_size, int total_frames) {
    if (buffer_size <= 0 || total_frames <= 0) return NULL;
    ScoreFeatureBuffers* buf = (ScoreFeatureBuffers*)malloc(sizeof(ScoreFeatureBuffers));
    if (!buf) return NULL;
    memset(buf, 0, sizeof(ScoreFeatureBuffers));
    buf->buffer_size = buffer_size;
    buf->total_frames = total_frames;
    // 分配各特征缓冲
    buf->pitch_buffer = (float*)calloc(buffer_size, sizeof(float));
    buf->energy_buffer = (float*)calloc(buffer_size, sizeof(float));
    buf->brightness_buffer = (float*)calloc(buffer_size, sizeof(float));
    buf->timbre_buffer = (float*)calloc(buffer_size, sizeof(float));
    buf->flux_buffer = (float*)calloc(buffer_size, sizeof(float));
    // 为基准特征缓冲区分配内存
    buf->pitch_buffer_base = (float*)calloc(buffer_size, sizeof(float));
    buf->energy_buffer_base = (float*)calloc(buffer_size, sizeof(float));
    buf->brightness_buffer_base = (float*)calloc(buffer_size, sizeof(float));
    buf->timbre_buffer_base = (float*)calloc(buffer_size, sizeof(float));
    buf->rhythm_buffer_base = (float*)calloc(buffer_size, sizeof(float));
    buf->vad_buffer_base = (float*)calloc(buffer_size, sizeof(float));
    if (!buf->pitch_buffer || !buf->energy_buffer || !buf->brightness_buffer ||
        !buf->timbre_buffer || !buf->flux_buffer || !buf->pitch_buffer_base ||
        !buf->energy_buffer_base || !buf->brightness_buffer_base ||
        !buf->timbre_buffer_base || !buf->rhythm_buffer_base || !buf->vad_buffer_base) {
        free_calculate_score_buffers(buf);
        return NULL;
    }
    return buf;
}

void free_calculate_score_buffers(ScoreFeatureBuffers* buffers) {
    if (!buffers) return;
    if (buffers->pitch_buffer) free(buffers->pitch_buffer);
    if (buffers->energy_buffer) free(buffers->energy_buffer);
    if (buffers->brightness_buffer) free(buffers->brightness_buffer);
    if (buffers->timbre_buffer) free(buffers->timbre_buffer);
    if (buffers->flux_buffer) free(buffers->flux_buffer);
    if (buffers->pitch_buffer_base) free(buffers->pitch_buffer_base);
    if (buffers->energy_buffer_base) free(buffers->energy_buffer_base);
    if (buffers->brightness_buffer_base) free(buffers->brightness_buffer_base);
    if (buffers->timbre_buffer_base) free(buffers->timbre_buffer_base);
    if (buffers->rhythm_buffer_base) free(buffers->rhythm_buffer_base);
    if (buffers->vad_buffer_base) free(buffers->vad_buffer_base);
    free(buffers);
}

/**
 * @brief 使用频谱通量检测句子起始点
 * 基于频谱通量的突变来检测语音/音乐的起始点
 */
int detect_onset_by_flux(const ScoreFeatureBuffers* buffers, int end_frame_idx, int search_range) {
    if (!buffers || !buffers->flux_buffer || end_frame_idx < 0 || 
        end_frame_idx >= buffers->buffer_size || search_range <= 0) {
        return -1;
    }
    
    // 获取当前句子的起始点
    if (sentence_start_idx < 0) {
        // 如果找不到句子起始点，直接返回-1
        return -1;
    }
    
    // 以句子起始点为中心，定义搜索范围
    int start_idx = sentence_start_idx - search_range / 2;
    int end_idx = sentence_start_idx + search_range / 2;
    
    // 确保搜索范围在有效边界内
    if (start_idx < 0) start_idx = 0;
    if (end_idx >= buffers->buffer_size) end_idx = buffers->buffer_size - 1;
    
    int range_size = end_idx - start_idx + 1;
    
    // 如果搜索范围太小，返回句子起始点
    if (range_size <= 3) return sentence_start_idx;
    
    // 用于存储处理后的频谱通量
    float* processed_flux = (float*)malloc(range_size * sizeof(float));
    if (!processed_flux) return sentence_start_idx; // 如果分配失败，返回句子起始点
    
    // 1. 提取搜索范围内的频谱通量
    for (int i = start_idx; i <= end_idx; i++) {
        processed_flux[i - start_idx] = buffers->flux_buffer[i];
    }
    
    // 2. 计算平均值和标准差，用于自适应阈值
    float mean = 0.0f;
    for (int i = 0; i < range_size; i++) {
        mean += processed_flux[i];
    }
    mean /= range_size;
    
    float std_dev = 0.0f;
    for (int i = 0; i < range_size; i++) {
        float diff = processed_flux[i] - mean;
        std_dev += diff * diff;
    }
    std_dev = sqrtf(std_dev / range_size);
    
    // 3. 计算自适应阈值 = 均值 + 1.5 * 标准差
    float threshold = mean + 1.5f * std_dev;
    
    // 4. 搜索满足阈值的最大峰值点
    int max_peak_idx = -1;
    float max_peak_value = 0.0f;
    
    for (int i = 1; i < range_size - 1; i++) {  // 跳过首尾点，确保可以比较前后点
        // 检查是否是峰值（比前后点都大）
        if (processed_flux[i] > processed_flux[i-1] && 
            processed_flux[i] > processed_flux[i+1] && 
            processed_flux[i] > threshold) {
            // 找到一个峰值，检查是否是最大峰值
            if (processed_flux[i] > max_peak_value) {
                max_peak_value = processed_flux[i];
                max_peak_idx = i;
            }
        }
    }
    
    // 5. 释放临时内存
    free(processed_flux);
    
    // 6. 如果找到峰值，返回对应的原始帧索引
    if (max_peak_idx >= 0) {
        return start_idx + max_peak_idx;
    }
    
    // 如果没有找到有效的onset点，返回句子起始点
    return sentence_start_idx;
}

/**
 * @brief 使用能量法检测句子起始点
 * 基于能量变化来检测语音/音乐的起始点
 */
int detect_onset_by_energy(const ScoreFeatureBuffers* buffers, int end_frame_idx, int search_range) {
    if (!buffers || !buffers->energy_buffer || end_frame_idx < 0 || 
        end_frame_idx >= buffers->buffer_size || search_range <= 0) {
        return -1;
    }
    
    // 获取当前句子的起始点
    if (sentence_start_idx < 0) {
        // 如果找不到句子起始点，直接返回-1
        return -1;
    }
    
    // 以句子起始点为中心，定义搜索范围
    int start_idx = sentence_start_idx - search_range / 2;
    int end_idx = sentence_start_idx + search_range / 2;
    
    // 确保搜索范围在有效边界内
    if (start_idx < 0) start_idx = 0;
    if (end_idx >= buffers->buffer_size) end_idx = buffers->buffer_size - 1;
    
    int range_size = end_idx - start_idx + 1;
    
    // 如果搜索范围太小，返回句子起始点
    if (range_size <= 3) return sentence_start_idx;
    
    // 用于存储能量差分
    float* energy_diff = (float*)malloc(range_size * sizeof(float));
    if (!energy_diff) return sentence_start_idx; // 如果分配失败，返回句子起始点
    
    // 1. 计算能量差分
    energy_diff[0] = 0.0f;  // 第一帧没有差分
    for (int i = start_idx + 1; i <= end_idx; i++) {
        /* 将 dB 能量值转换为线性能量值 (P = 10^(dB/10)) */
        float e_curr = powf(10.0f, buffers->energy_buffer[i]     / 10.0f);
        float e_prev = powf(10.0f, buffers->energy_buffer[i - 1] / 10.0f);

        // 计算正向能量差分（只保留能量上升部分）
        float diff = e_curr - e_prev;
        energy_diff[i - start_idx] = (diff > 0.0f) ? diff : 0.0f;
    }
    
    // 2. 计算平均值和标准差，用于自适应阈值
    float mean = 0.0f;
    for (int i = 0; i < range_size; i++) {
        mean += energy_diff[i];
    }
    mean /= range_size;
    
    float std_dev = 0.0f;
    for (int i = 0; i < range_size; i++) {
        float diff = energy_diff[i] - mean;
        std_dev += diff * diff;
    }
    std_dev = sqrtf(std_dev / range_size);
    
    // 3. 计算自适应阈值 = 均值 + 2.0 * 标准差
    float threshold = mean + 2.0f * std_dev;
    
    // 4. 搜索满足阈值的最大峰值点
    int max_peak_idx = -1;
    float max_peak_value = 0.0f;
    
    for (int i = 1; i < range_size - 1; i++) {  // 跳过首尾点
        // 检查是否是峰值（比前后点都大）
        if (energy_diff[i] > energy_diff[i-1] && 
            energy_diff[i] > energy_diff[i+1] && 
            energy_diff[i] > threshold) {
            // 找到一个峰值，检查是否是最大峰值
            if (energy_diff[i] > max_peak_value) {
                max_peak_value = energy_diff[i];
                max_peak_idx = i;
            }
        }
    }
    
    // 5. 释放临时内存
    free(energy_diff);
    
    // 6. 如果找到峰值，返回对应的原始帧索引
    if (max_peak_idx >= 0) {
        return start_idx + max_peak_idx;
    }
    
    // 如果没有找到有效的onset点，返回句子起始点
    return sentence_start_idx;
}

/**
 * @brief 通过基准文件的节奏值检测句子起始点
 * 当节奏值为1时表示句子开始
 */
int detect_sentence_start_by_rhythm(const ScoreFeatureBuffers* buffers, int end_frame_idx) {
    if (!buffers || !buffers->rhythm_buffer_base || 
        end_frame_idx < 0 || end_frame_idx >= buffers->buffer_size) {
        return -1;
    }
    
    // 从结束点向前搜索，找到最近的句子起始点（rhythm_buffer_base值为1的点）
    for (int i = end_frame_idx; i > 0; i--) {
        // 如果遇到另一个句尾标记(rhythm=2)，则认为异常（句子嵌套）
        if (buffers->rhythm_buffer_base[i] == 2 && i != end_frame_idx) {
            return -1;
        }
        
        // 找到句子开始点
        if (buffers->rhythm_buffer_base[i] == 1) {
            return i;
        }
    }
    // 如果搜索到索引0仍未找到句子起始点，返回-1
    return -1;
}